﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Razre.Events;

namespace Razre
{
    /// <summary>
    /// Class to provide management and activation of Themes
    /// </summary>
    public static class ThemeManager
    {
        #region ctors

        /// <summary>
        /// Default Constructor to initialize the master dictionary and add it to the resources
        /// </summary>
        static ThemeManager()
        {
            Themes = new List<Theme>();
            MasterDictionary = new ResourceDictionary();

            //Add the dictionary used for theme management to application resources
            Application.Current.Resources.MergedDictionaries.Add(MasterDictionary);
        }

        #endregion

        #region private properties

        /// <summary>
        /// Collection of Loaded Themes
        /// </summary>
        private static List<Theme> Themes { get; set; }

        /// <summary>
        /// Static store for the Master Dictionary
        /// </summary>
        private static ResourceDictionary MasterDictionary { get; set; }

        #endregion

        #region methods

        /// <summary>
        /// Method will load a Theme into the theme management system
        /// </summary>
        /// <param name="name">Name of the theme to be used</param>
        /// <param name="dictionaryLocation">Location of the ResourceDictionary containing the Theme</param>
        /// <returns>Returns if Loading the Theme was succesful</returns>
        public static void LoadTheme(string name, Uri dictionaryLocation)
        {
            try
            {
                //try to find the resource dictionary by location
                ResourceDictionary themeFile = new ResourceDictionary();
                themeFile.Source = dictionaryLocation;

                //load the theme by resource dictionary
                LoadTheme(name, themeFile);
            }
            catch (Exception ex)
            {
                throw new Exception("Error Occurred Loading a Theme by URI, please see inner exception for details", ex);
            }
        }

        /// <summary>
        /// Method will load a Theme into the theme management system
        /// </summary>
        /// <param name="name">Name of the theme to be used</param>
        /// <param name="themeFile">ResourceDictionary containing the Theme</param>
        /// <returns>Returns if Loading the Theme was successful</returns>
        public static void LoadTheme(string name, ResourceDictionary themeFile)
        {
            try
            {
                //check to see if a theme with the same name exists
                Theme loadedTheme = (from theme in Themes
                                     where theme.Name == name
                                     select theme).FirstOrDefault();

                //if it doesnt exist
                if (loadedTheme == null)
                {
                    //create a theme and add it to the store
                    Theme theme = new Theme();
                    theme.Name = name;
                    theme.ResourceDictionary = themeFile;

                    Themes.Add(theme);

                }
                else
                {
                    //if the theme existed and is currently loaded, replace it
                    if (MasterDictionary.MergedDictionaries.Contains(loadedTheme.ResourceDictionary))
                    {
                        MasterDictionary.MergedDictionaries.Remove(loadedTheme.ResourceDictionary);
                        MasterDictionary.MergedDictionaries.Add(themeFile);
                    }

                    //replaced the stored theme's dictionary with the new one
                    loadedTheme.ResourceDictionary = themeFile;                    
                }
            }
            catch (Exception ex)
            {
                throw new Exception("An Error has occurred while loading a theme by resource dictionary.  Please see inner exception for details", ex);
            }
        }

        /// <summary>
        /// Method to set a theme that is already loaded
        /// </summary>
        /// <param name="name">Name of the theme to set</param>
        /// <returns>Returns if setting the theme was successful</returns>
        public static void SetTheme(string name)
        {
            try
            {
                //try to find the loaded theme
                Theme loadedTheme = (from theme in Themes
                                     where theme.Name == name
                                     select theme).FirstOrDefault();

                //if the theme was found
                if (loadedTheme != null)
                {
                    //make sure the theme isnt loaded
                    if (!MasterDictionary.MergedDictionaries.Contains(loadedTheme.ResourceDictionary))
                    {
                        //if a theme was already loaded, remove it
                        if (MasterDictionary.MergedDictionaries.Count > 0)
                        {
                            MasterDictionary.MergedDictionaries.RemoveAt(0);
                        }

                        //add the theme to load
                        MasterDictionary.MergedDictionaries.Add(loadedTheme.ResourceDictionary);

                        //notify view models that the theme has changed through the settings event aggregator
                        Settings.EventAggregator.GetEvent<ThemeChangedEvent>().Publish(true);
                    }
                }
                else
                    throw new Exception("Theme was not loaded");
            }
            catch (Exception ex)
            {
                throw new Exception("An Exception occurred while trying to set a theme.  Please see inner exception for details.", ex);
            }
        }

        #endregion
    }

    /// <summary>
    /// Data Class to provide the configuration of a Theme
    /// </summary>
    public class Theme
    {
        /// <summary>
        /// ResourceDictionary holding the theme information
        /// </summary>
        public ResourceDictionary ResourceDictionary { get; set; }

        /// <summary>
        /// Name of the theme
        /// </summary>
        public string Name { get; set; }
    }
}
